You exec into a running container using the docker exec -it command, which starts a new process inside the container, typically a shell for interactive debugging or administration.
The docker exec command allows you to run a new command or process inside an already running container. This is the primary method for debugging, inspecting files, checking logs, or performing administrative tasks without stopping the container. The most common use is docker exec -it <container> /bin/sh (or /bin/bash if available) to get an interactive shell inside the container, enabling exploration of the filesystem, checking environment variables, or testing application behavior in the runtime environment.
The -it flags are essential for interactive sessions: -i keeps STDIN open (allowing you to type), and -t allocates a pseudo-TTY (giving you a proper terminal interface). Without these, you'd run a command and exit immediately. The container must be running to exec into it—you cannot exec into stopped containers (use docker start first).
When you exec into a container, you're creating a new process inside the container's namespaces. This process runs with the container's root filesystem and shares the same network, PID, and mount namespaces. However, it's important to note that docker exec does not require the container to have a shell installed; you can run any executable present in the container's filesystem. For minimal images like Alpine, /bin/sh is typically available; for Distroless images, you may need to use docker cp or other debugging techniques.
docker exec -it my-app /bin/sh - Get a shell to explore the container's filesystem
docker exec my-app cat /etc/os-release - Check what OS the container is running
docker exec my-app env - View environment variables set in the container
docker exec -d my-app npm run db:seed - Run a background task in a running container
docker exec --user www-data my-app php artisan cache:clear - Run commands as a specific user
Security considerations: Anyone with access to the Docker socket can exec into any container, effectively gaining root access to the host. In production, restrict access to the Docker daemon and consider using --user to exec with non-root privileges when possible. For debugging containers built from distroless or scratch images that lack shells, you can use docker cp to copy files out, or run a sidecar container with debugging tools sharing the same PID namespace using --pid=container:<container-id>.